"""
# --- 经常需要更新的基址

# 玩家自己的偏移
my_client_offset


# 玩家数量
num_of_humans_offset


# 人物地址链表偏移
client_dll_offset_human

# 转换矩阵基址
transformation_array_offset
"""

import pymem
import win32api
import win32gui
import win32process
import win32con
from bdtime import tt

from bdtime.my_log import log_config_dc
import logging
logging.basicConfig(**log_config_dc.usual)
log = logging.getLogger(__file__)


window_title = "反恐精英：全球攻势"
_client_dll_name = "client.dll"
WindowHandle = win32gui.FindWindow(None, "反恐精英：全球攻势")
if not WindowHandle:
    _client_dll_name = "server.dll"
    window_title = "Counter-Strike 2"
    WindowHandle = win32gui.FindWindow(None, "Counter-Strike 2")  # steam开启的cs2


flag__move_window_to_left_top = 0
if flag__move_window_to_left_top:
    # 4. 获取窗口当前的位置和大小（避免移动时改变窗口尺寸）
    # GetWindowRect返回值：(left, top, right, bottom) → 宽=right-left，高=bottom-top
    left, top, right, bottom = win32gui.GetWindowRect(WindowHandle)
    window_width = right - left  # 窗口宽度（保持不变）
    window_height = bottom - top  # 窗口高度（保持不变）

    # 5. （可选）若窗口处于最小化状态，先恢复正常显示（否则移动无效）
    if win32gui.IsIconic(WindowHandle):
        win32gui.ShowWindow(WindowHandle, win32con.SW_RESTORE)  # SW_RESTORE=9，恢复窗口

    win32gui.MoveWindow(WindowHandle, 0, 0, window_width, window_height, True)

    print(f"成功：窗口「{window_title}」已移动到屏幕左上角！")
    exit()


ThreadId, ProcessId = win32process.GetWindowThreadProcessId(WindowHandle)
PROCESS_ALL_ACCESS = (0x000F0000 | 0x00100000 | 0xFFF)
ProcessHandle = pymem.process.open(ProcessId, True, PROCESS_ALL_ACCESS)
client_dll = pymem.process.module_from_name(ProcessHandle, _client_dll_name).lpBaseOfDll
real_client_dll = pymem.process.module_from_name(ProcessHandle, "client.dll").lpBaseOfDll

'''游戏更新需替换的部分--开始'''
def read_point_by_multi_offsets(process_handle, dll, offset_ls: [int, list], read_type=pymem.memory.read_longlong):
    """
    除了单一偏移, 再支持读取多级偏移的指针
    """
    if isinstance(offset_ls, int):
        point_address = pymem.memory.read_longlong(process_handle, dll + offset_ls)
        hex(point_address)
        return point_address

    point_address = dll
    for offset_i in offset_ls:
        point_address += offset_i
        point_address = pymem.memory.read_longlong(process_handle, point_address)
        # point_address = read_type(process_handle, point_address)
    return point_address


# 玩家自己的偏移
my_client_offset = 0x17AE140


# 玩家数量
num_of_humans_offset = 0x17AE12C


# --- 这里测试下是否能读取, 如果错了(Winapi Error)就是基址要更新了
num_of_humans_value = pymem.memory.read_int(ProcessHandle, client_dll + num_of_humans_offset)
my_client_address = read_point_by_multi_offsets(ProcessHandle, client_dll, my_client_offset)
log.debug(f"--- hex(my_client_address): {hex(my_client_address)}")


# 自己血量偏移 ok
my_blood_offset = 0x2d0


# 自己z的client偏移 ok
my_x_client_offset = 0x870
# 自己y的client偏移
my_y_client_offset = my_x_client_offset + 0x4
# 自己x的client偏移
my_z_client_offset = my_y_client_offset + 0x4

# 视角地址偏移
client_dll_offset_x = 0xc90
client_dll_offset_y = client_dll_offset_x + 0x4

# 人物地址链表偏移
client_dll_offset_human = 0x1752208
# client_dll_offset_human = [0x01748088, 0]

# x坐标偏移
x_offset = my_x_client_offset
# y坐标偏移
y_offset = x_offset + 0x4
# z坐标偏移
z_offset = y_offset + 0x4
# 血量偏移
blood_offset = my_blood_offset

# --- 可能可以用于判断阵营的基址偏移
# side_tag_offset = 0x33c
# side_tag_offset = 0x750
side_tag_offset = 0x83C  # 1
# side_tag_offset = 0xa80  # 2
# side_tag_offset = 0x938  # 3
# side_tag_offset = 0xDDC
# side_tag_offset = 0xFF0


# --- 这个是使用字符串来判断是否队友, 还是有bug存在...
use_map_for_tag = 1
# use_map_for_tag = 0

string_side_tag_offset = 0xf28

# 转换矩阵基址
transformation_array_offset = 0x1E32B48


'''游戏更新需替换的部分--结束'''

DC = win32gui.GetDC(0)
# 创建DC的画板
CDC = win32gui.CreateCompatibleDC(DC)
# 创建画布
bmp = win32gui.CreateCompatibleBitmap(DC, 50, 50)
# 将画布加入画板中
win32gui.SelectObject(CDC, bmp)

brush_for_one_side = win32gui.CreateSolidBrush(win32api.RGB(0, 0, 255))
brush_for_other_side =  win32gui.CreateSolidBrush(win32api.RGB(0, 255, 0))
brush = win32gui.CreateSolidBrush(win32api.RGB(0, 255, 0))


# 人物数组起始地址
human_array_address = client_dll + client_dll_offset_human
human_array = read_point_by_multi_offsets(ProcessHandle, client_dll, client_dll_offset_human)
print(f"===== client_dll[{hex(client_dll)}] + client_dll_offset_human[{hex(client_dll_offset_human)}] = human_array_address[{hex(human_array_address)}] -> human_array[{hex(human_array)}]")
assert human_array != 0, f"human_array should not equal zero!"


def judge_string_side_tag_is_ct(string_side_tag: str):
    side_tag_ls = ["TSpawn", "CTSpawn"]
    if string_side_tag not in side_tag_ls:
        return None

    if string_side_tag == side_tag_ls[0]:
        return 0
    else:
        return 1


kv_maps = {}

show_t_1 = show_t_0 = tt.now()
show_text_map = {}
rect_map = {}

flag__ignore_num_of_humans_value = 10  # 是否忽略`num_of_humans_value`, 强制绘n个方框. 调试用
while True:
    try:
        tt.sleep(0.001)
        num_of_humans_value = pymem.memory.read_int(ProcessHandle, client_dll + num_of_humans_offset)

        if num_of_humans_value <= 1:
            if flag__ignore_num_of_humans_value:
                num_of_humans_value = 10
            else:
                print(f"num_of_humans_value == 0, time: {tt.now(0)}, continue...")
                tt.sleep(1)
                continue

        transformation_array_address = real_client_dll + transformation_array_offset

        def get_transformation_array(transformation_array_address, array_mn=(3, 4), debug_info=False):
            transformation_array_list = []

            for i in range(array_mn[0]):
                _ls = []
                for j in range(array_mn[1]):
                    k = i * array_mn[1] + j
                    _value = pymem.memory.read_float(ProcessHandle, transformation_array_address + (k * 4))
                    _ls.append(round(_value, 3))
                transformation_array_list.append(_ls)
                if debug_info:
                    print(f'---------- get_transformation_array [{i}]: ', _ls)

            return transformation_array_list

        transformation_array = get_transformation_array(transformation_array_address)
        # transformation_array = get_transformation_array(transformation_array_address, debug_info=True)

        other_side_tag_string = my_side_tag_string = None

        for i in range(num_of_humans_value):
            human_offset = i * 0x8
            other_address = human_array + human_offset
            other_array = pymem.memory.read_longlong(ProcessHandle, other_address)

            # 读其他人的血量
            try:
                blood_address = other_array + blood_offset
                print(f"\n{i} --- 尝试读取的地址 blood_address: 0x{blood_address:X}")
                other_blood = pymem.memory.read_int(ProcessHandle, other_array + blood_offset)
            # except pymem.exception.WinAPIError as e:
            #     print(f"读取内存失败: {e}")
            #     print(f"错误代码: {e.error_code}")
            #     print(f"地址: 0x{blood_address:X}")
            except Exception as e:
                print(f"--- filter human[{i}] by cannot read memory blood! error: {e}")
                continue

            if i == 2:
                print(f'--- i: {i}')

            k_name = f"other_side_tag-{i}"
            k_name_for_tag_string = f'other_side_tag_string-{i}'
            if use_map_for_tag:
                other_side_tag = kv_maps.get(k_name)
                other_side_tag_string = kv_maps.get(k_name)

                # if other_blood == 82:
                #     print(f'other_blood: {other_blood} --- k_name: {k_name} --- other_side_tag: {other_side_tag}, other_side_tag_string: {other_side_tag_string}')

                try:
                    if other_side_tag is None:
                        other_side_tag_string = pymem.memory.read_string(ProcessHandle, other_array + string_side_tag_offset)  # 其他人阵营标签
                        other_side_tag = judge_string_side_tag_is_ct(other_side_tag_string)
                        kv_maps.update({k_name: other_side_tag})
                        kv_maps.update({k_name_for_tag_string: other_side_tag_string})
                except Exception as e:
                    if flag__ignore_num_of_humans_value:
                        other_side_tag = 1
                    else:
                        print(f"--- filter human_[{i}] by other_side_tag error, other_side_tag: {other_side_tag}, error: {e}")
                        continue
            else:
                other_side_tag = pymem.memory.read_int(ProcessHandle, other_array + side_tag_offset)  # 其他人阵营标签

            if other_blood <= 0:
                print(f"--- filter human_[{i}] by other_blood < 0, other_blood: {other_blood} ---")
                continue
            # if other_blood > 100:
            #     print(f"--- filter human_[{i}] by other_blood > 100, other_blood: {other_blood} ---")
            #     continue

            print(f"----- 绘制 human_[{i}]")

            rect = win32gui.GetWindowRect(WindowHandle)

            left, top, right, bottom = rect
            screen_width = right - left  # 屏幕宽
            screen_height = bottom - top  # 屏幕高

            # 读取自己client，用于血量
            # my_client = pymem.memory.read_longlong(ProcessHandle, client_dll + my_client_offset)
            my_client = read_point_by_multi_offsets(ProcessHandle, client_dll, my_client_offset)  # 多级指针读取

            if my_client == other_array:
                print(f"--- filter: 过滤掉自己 hex(my_client)[{hex(my_client)}] == hex(other_array)[{hex(other_array)}]")
                continue

            k_name = "my_side_tag"
            if use_map_for_tag:
                my_side_tag = kv_maps.get(k_name)
                try:
                    if my_side_tag is None :
                        my_side_tag_string = pymem.memory.read_string(ProcessHandle, my_client + string_side_tag_offset)  # 其他人阵营标签
                        my_side_tag = judge_string_side_tag_is_ct(my_side_tag_string)
                        kv_maps.update({k_name: my_side_tag})
                except Exception as e:
                    if flag__ignore_num_of_humans_value:
                        my_side_tag = 0
                    else:
                        print(f"--- filter human_[{i}] by my_side_tag error, my_side_tag: {my_side_tag}, error: {e}")
                        continue
            else:
                my_side_tag = pymem.memory.read_int(ProcessHandle, my_client + side_tag_offset)  # 其他人阵营标签

            flag__draw_other_side = True
            flag__draw_one_side = True
            is_same_side = True

            # if other_side_tag not in [2, 3]:
            #     print(f"--- filter human_[{i}] by other_side_tag [{other_side_tag}] not in [2, 3], other_blood: {other_blood} --- flag__draw_other_side: {flag__draw_other_side}")
            #     continue

            if other_side_tag != my_side_tag:  # 剔除[观战者]等标签, 并过滤掉队友
                is_same_side = False

            print(f'--- other_side_tag: {other_side_tag}, my_side_tag: {my_side_tag}, equal: {other_side_tag != my_side_tag}')

            if is_same_side:
                if not flag__draw_one_side:
                    print('--- filter by not flag__draw_one_side')
                    continue
            else:
                if not flag__draw_other_side:
                    print('--- filter by not flag__draw_other_side')
                    continue

            brush = brush_for_one_side if is_same_side else brush_for_other_side

            print(f"\n----- start draw rect for human_[{i}], other_blood: {other_blood}, is_same_side: {is_same_side}")

            my_x = pymem.memory.read_float(ProcessHandle, my_client + my_x_client_offset)
            # 读取自己y
            my_y = pymem.memory.read_float(ProcessHandle, my_client + my_y_client_offset)
            # 读取自己z
            my_z = pymem.memory.read_float(ProcessHandle, my_client + my_z_client_offset)

            # 读取FOV_xs
            fov_x = pymem.memory.read_float(ProcessHandle, my_client + client_dll_offset_x)
            # 读取FOV_y
            fov_y = pymem.memory.read_float(ProcessHandle, my_client + client_dll_offset_y)

            # 读其他人x
            other_x = pymem.memory.read_float(ProcessHandle, other_array + x_offset)
            # 读其他人y
            other_y = pymem.memory.read_float(ProcessHandle, other_array + y_offset)
            # 读其他人z
            other_z = pymem.memory.read_float(ProcessHandle, other_array + z_offset)

            from get_screen_position import get_screen_position
            from get_screen_position import draw_rect_by_position
            from get_screen_position import draw_text_by_position
            from get_screen_position import clamp_rect_to_window

            print(f"my_x: {my_x:.2f}, my_y: {my_y:.2f}, my_z: {my_z:.2f}, "
                  f"other_x: {other_x:.2f}, other_y: {other_y:.2f}, other_z: {other_z:.2f}, "
                  f"fov_x: {fov_x:.2f}, fov_y: {fov_y:.2f}, "
                  f"screen_width: {screen_width}, screen_height: {screen_height}")
            print(
                f"--- human_array[{hex(human_array)}] + human_offset[{hex(human_offset)}] = other_address: {hex(other_address)} -> other_array[{hex(other_array)}]")

            success_flag, (x0, y0, x1, y1) = get_screen_position(other_x, other_y, other_z, screen_width, screen_height, transformation_array)

            # real_rect = (x0 + left, y0 + top, x1 + left, y1 + top)
            # new_rect = (x0, y0, x1, y1)
            # old_rect = rect_map.get(i, new_rect)
            # rect_map.update({i: new_rect})

            show_t_1 = tt.now()
            last_show_time = show_text_map.get(i, -1)

            show_interval = show_t_1 - last_show_time

            real_rect = clamp_rect_to_window((x0, y0, x1, y1), rect)

            if success_flag:
                draw_rect_by_position(DC, CDC, *real_rect, 2, brush)

                other_side_tag_string = kv_maps.get(k_name_for_tag_string)

#                 text = f"""human-{i}
# blood: {other_blood}
# is_same_side: {is_same_side}
# is_ct: {other_side_tag}
# side_tag: {other_side_tag_string}
# """
                side_name = "CT" if other_side_tag else "T"
                # text = f"{side_name}-{i}__{other_blood}"
                text = f"{other_blood}"
                font_size = 24
                draw_text_by_position(DC, CDC, *real_rect, 2, text=text, font_size=font_size)

                # if show_interval > 0.1:
                #     # rect_distance = get_distance_for_2_rect(old_rect, new_rect)
                #     # if rect_distance > 0.01:
                #
                #     draw_text_by_position(DC, CDC, *real_rect, 2, text=text, font_size=font_size)
                #     show_text_map.update({i: show_t_1})

            # break
        # break
    except Exception as e:
        print(f'***** Run Error: {e}')
        import traceback
        traceback.print_exc()
        continue

